#include "trainer.h"

#include <QFile>
#include <QList>
#include <QDebug>
#include <QJsonObject>
#include <QTime>


#include "util.h"

using namespace std;

Trainer::Trainer(QObject *parent)
	: QObject(parent)
{
	codec = QTextCodec::codecForName("UTF-8");
}

Trainer::~Trainer()
{
	
}

Trainer::Trainer()
{
	codec = QTextCodec::codecForName("UTF-8");
}

void Trainer::parserStarUpXml(QString path)
{
    QFile file(path);
    if (file.open(QIODevice::ReadOnly | QIODevice::Text)){

        //构建QXmlStreamReader对象
        QXmlStreamReader reader(&file);
        while (!reader.atEnd()){
            
            if (reader.isStartElement()) {
                if (reader.name() == "learn") {
                    QString filename = reader.readElementText();
                    //qDebug() << "bot learn :" << filename;
                    QStringList list  =  learn(filename);
                    _patternMap[filename] = list;
                }
            }
            reader.readNext();
        }
        file.close();

    }

}

QStringList Trainer::learn(QString filename)
{
    QStringList list;
    QFile file("aiml/"+filename);

    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {

        //构建QXmlStreamReader对象
        QXmlStreamReader reader(&file);
        while (!reader.atEnd()) {
            
            if (reader.isStartElement()) {
                /*qDebug() << "Tag name:" << reader.name();*/
                if (reader.name() == "category") {
                    QString pattern =  parserCategory(reader);
                    if (!pattern.isEmpty()){list.append(pattern);}
                }
            }
            reader.readNext();
        }
        file.close();

    }

    return list;
}

QString Trainer::parserCategory(QXmlStreamReader& reader)
{
    QString _pattern, _template;
    while (!reader.atEnd()) {

        
        if (reader.isStartElement()) {

           
            if (reader.name() == "pattern") {
                _pattern = reader.readElementText();
                _pattern.remove(QChar('\n'), Qt::CaseInsensitive);
                _pattern.remove(QChar('\t'), Qt::CaseInsensitive);
                _pattern.remove(QChar('\r'), Qt::CaseInsensitive);
                //qDebug() << "_pattern: " << _pattern;
            }
            if (reader.name() == "template") {
                reader.readNext();
                if (reader.isCharacters()) {
                    QByteArray text = reader.text().toUtf8();
                    //qDebug() << "text:" << text;
                    _template = QString(text);
                    _template.remove(QChar('\n'), Qt::CaseInsensitive);
                    _template.remove(QChar('\t'), Qt::CaseInsensitive);
                    _template.remove(QChar('\r'), Qt::CaseInsensitive); 
                        //qDebug() << "_template: " << _template;
                }

            } 
        } 
        if (reader.isEndElement() && reader.name() == "category") {
            break;
        }
        reader.readNext();

    }

    if (!_pattern.isEmpty()) {

        QUuid uuid = Trainer::getUUid();
        MEMINFOS info;
        info.pattern = _pattern;
        info.content = _template;
        _map[uuid] = info;
        qDebug() << " pattern:" << _pattern << " content:" << _template ;
 
    }
    
    return _pattern;

}

QUuid Trainer::getUUid()
{
    return QUuid::createUuid();
}

QList<Response::resultStruct> Trainer::get_response(QString input)
{
    QList<Response::resultStruct> list;
    int count = 0;
    for(MEMINFOS var : _map){
        QString pattern = var.pattern;
        float p =1.0-1.0*calcDistance(input, pattern)/(pattern.length() + input.length());
        if (p>=0.9) {
            qDebug() << "match " << p * 100 << "%";
            Response::resultStruct result = prehandle(var.content);
            list.append(result);
            break;
        }else if(p>=0.75 && pattern.contains(input)){
            qDebug() << "match " << p * 100 << "%";
            Response::resultStruct result = prehandle(var.content);
            list.append(result);
            if (++count < 3) {
                break;
            }
        }
 
    }
    
    if (list.count()==0) {
        Response::resultStruct result ;
        result.resultType = "text";
        //result.content = QStringLiteral("我没有想出这个问题的答案<@_@>，我可以学习喽，通过上传知识库，我会变得更加的强大!");
		result.content = codec->toUnicode("我没有想出这个问题的答案<@_@>，我可以学习喽，通过上传知识库，我会变得更好");
        list.append(result);
    }

    return list;


}

Response::resultStruct Trainer::prehandle(QString text)
{
    Response::resultStruct  result;
    QJsonObject data = Util::matchJsonString(text);
    if (data.isEmpty()) {
        result.resultType = "text";
        if (text.isEmpty() || text =="") {
			QTextCodec *codec = QTextCodec::codecForName("UTF8");
            result.content = codec->toUnicode("我没有想出这个问题的答案<@_@>，我可以学习喽，通过上传知识库，我会变得更好");
        }else {
            result.content = text;
        }
        return  result;
    }

    if (data.contains("time")) {
        result.resultType = "text";
        result.content = Util::getCurrentDateTime();
        return  result;
    }
    if (data.contains("city-weather")) {
        QString city = data.value("city-weather").toString();
        result.resultType = "text";
        result.content = Util::getWeather(city);
        return  result;
    }
    if (data.contains("url")) {
        result.resultType = "url";
        result.content = data["url"].toString();
        return  result;
    }

    if (data.contains("oss-filename")) {
        result.resultType = "url";
        QString filename = data["oss-filename"].toString();
        result.content = Util::getOssUrl(filename);
        return  result;
    }

    if (data.contains("random")) {

        QString content  = Util::parserRandom(data.value("random"));
        result.resultType = "text";
        result.content = content;
        return  result;
    }

    
    
    result.resultType = "text";
    result.content = codec->toUnicode("未知的错误!");
    return  result;
}



int Trainer::calcDistance(const QString source, const QString target)
{
  
    int n = source.length();
    int m = target.length();
    if (m == 0) return n;
    if (n == 0) return m;
    QVector <QVector <int>> matrix(n + 1);
    for (int i = 0; i <= n; i++) matrix[i].resize(m + 1);
    for (int i = 1; i <= n; i++) matrix[i][0] = i;
    for (int i = 1; i <= m; i++) matrix[0][i] = i;
    for (int i = 1; i <= n; i++)
    {
        const QChar si = source.at(i - 1);
        for (int j = 1; j <= m; j++)
        {
            const QChar dj = target.at(j - 1);
            int cost;
            if (si == dj)
                cost = 0;
            else
                cost = 1;
            const int above = matrix[i - 1][j] + 1;
            const int left = matrix[i][j - 1] + 1;
            const int diag = matrix[i - 1][j - 1] + cost;
            matrix[i][j] = min(above, min(left, diag));
        }
    }
    return matrix[n][m];
}

QStringList Trainer::findPatterns(QString filename)
{
    if (_patternMap.contains(filename)) {
        return _patternMap.value(filename);
    }
    return QStringList();
}

QStringList Trainer::getPatternKeys()
{
    return _patternMap.keys(); 
}
